//
//  DragDestinationView.swift
//  fir-mac
//
//  Created by dahua Liu on 2022/8/11.
//

import Cocoa

@objc protocol DragDestinationViewDelegate: NSObjectProtocol {
    @objc optional func processImage(_ image: NSImage, pasteBoard: NSPasteboard)
    
    @objc optional func process(_ obj: Any, pasteBoard: NSPasteboard)
    
    @objc optional func callback(urlStr: String)
}

///拖拽目标视图
@available(macOS 10.13, *)
class DragDestinationView: NSView {
    
    var delegate: DragDestinationViewDelegate?
    ///支持拖入的类型
    var supportedTypes: [NSPasteboard.PasteboardType] = [.color, .string, .fileURL, .html]{
        willSet{
            self.registerForDraggedTypes(newValue)
        }
    }
    ///支持拖入的子类型
    var acceptableUTITypes: [NSPasteboard.ReadingOptionKey : Any] {
        let types = [NSImage.imageTypes,
                     NSString.readableTypeIdentifiersForItemProvider,
                     NSURL.readableTypeIdentifiersForItemProvider].flatMap { $0 }
        return [NSPasteboard.ReadingOptionKey.urlReadingContentsConformToTypes : types]
    }
    
    var isReceivingDrag = false {
        didSet {
            needsDisplay = true
        }
    }
    
    override func awakeFromNib() {
        registerForDraggedTypes([.URL, .fileURL])
    }
    
    // MARK: -lifecycle
    convenience init(types: [NSPasteboard.PasteboardType]) {
        self.init()
        self.registerForDraggedTypes(types)
    }
        
    // MARK: -drag
    override func draggingEntered(_ sender: NSDraggingInfo) -> NSDragOperation {
        //加个判断，只有App才能拖进去被识别
        let pastboard = sender.draggingPasteboard
        guard let urlStr = pastboard.propertyList(forType: .fileURL) as? NSMutableString else {
            return []
        }
        if let path = URL(string: urlStr as String)?.path {
            if path.hasSuffix(".app") {
                return .copy
            }
        }
        return []
    }
    
    override func draggingExited(_ sender: NSDraggingInfo?) {
//        isReceivingDrag = false
    }
    
    override func prepareForDragOperation(_ sender: NSDraggingInfo) -> Bool {
        let pastboard = sender.draggingPasteboard
        guard let urlStr = pastboard.propertyList(forType: .fileURL) as? NSMutableString else {
            return false
        }
        if let path = URL(string: urlStr as String)?.path {
            DispatchQueue.global().async {
                self.delegate?.callback?(urlStr: path)
            }
            return true
        }
        return false
    }
}

public extension NSPasteboard{
    ///获取拖拽元素的信息
    @available(OSX 10.13, *)
    var propertyList: [Any]? {
        if let board = self.propertyList(forType: NSPasteboard.PasteboardType(rawValue: "NSFilenamesPboardType")) as? [String] {
            print("FILE: \(board)")
            return board
        }
        
        if let board = self.propertyList(forType: .URL) as? [URL] {
            print("URL: \(board)")
            return board
        }
        
        if let board = self.propertyList(forType: .string) as? [String] {
            print("STRING: \(board)")
            return board
        }
        
        if let board = self.propertyList(forType: .html) as? [String] {
            print("HTML: \(board)")
            return board
        }
        return nil
    }
    
    ///拖拽的本地文件路径
    @available(OSX 10.13, *)
    var draggedFileURL: NSURL? {
        if let property = propertyList?.first as? String {
            print(property)
            return NSURL(fileURLWithPath: property)
        }
        return nil
    }
    ///解析拖拽到目标视图上的信息同时options 参数限制可拖入子元素的类型（ nil 表示不限类型）
    func readObjects(forClasses classArray: [AnyClass] = [NSImage.self, NSColor.self, NSString.self, NSURL.self],
                     options: [NSPasteboard.ReadingOptionKey : Any]? = nil,
                     handler: ((Any)->Void)? = nil) -> Bool {
        guard let pasteboardObjects = readObjects(forClasses: classArray, options: options),
              pasteboardObjects.count > 0 else {
            return false
        }
        
        pasteboardObjects.forEach { (obj) in
            switch obj {
            case let value as NSImage:
                print(#function, #line, "NSImage", value)
                handler?(value)
                
            case let value as NSString:
                print(#function, #line, "NSString", value)
                handler?(value)

            case let value as NSColor:
                print(#function, #line, "NSColor", value)
                handler?(value)

            case let value as URL:
                print(#function, #line, "URL", value.absoluteString.removingPercentEncoding ?? "")
                if let image = NSImage(contentsOfFile: value.path) {
                    print(#function, #line, image)
                    handler?(image)
                } else {
                    handler?(value)
                }
                
            default:
                print(#function, #line, obj)
                handler?(obj)
                break
            }
        }
        return true
    }
}
